import wx
from Constant import *
from PublicMethod import *
'''
Basic_FallingObj :

    Used for falling object, when there is no obstacle at down, the object will fall down until encounter 
    
    the obstacle.In addition, if there is a obstacle at down, but the object type at down is belong to the
    
    table - LIST_DOWN_OBJ_FALL_LR, system will check whether there is no obstacle at left down / right down,
    
    is so, moving falling object to left / right direction. When this object is falling down now,and there is
    
    a object-A which is in table - LIST_CREATURE, it will be bursting from the center of this object.
'''
class Basic_FallingObj():
    '''
    Constructor : Basic_FallingObj
        mainMap : object pointer - MainMap
        pos - current position of this object in map (row, column)
        objType - object type of this
    '''
    def __init__(self, mainMap, pos, objType):
        self._001_initialInstanceVariable(mainMap, pos, objType)
        self._002_bindAction()
        self.timer_falling.Start(PublicMethod.ACT003_getRandomNum(900, 1200))
        self.timer_checkStopFalling.Start(200)
    '''
    function _001 : initialize the variables used for this object
        mainMap : object pointer - MainMap
        pos - current position of this object in map (row, column)
        objType - object type of this
    '''
    def _001_initialInstanceVariable(self, mainMap, pos, objType):
        #object pointer - MainMap
        self.mainMap = mainMap
        #record current position in map (row, column)
        self.posInMap = pos
        #record object type
        self.objType = objType
        #record whether this is falling now
        self.isFalling = False
        #timer of check and do/not do falling
        self.timer_falling = wx.Timer()
        #timer of check whether it stops falling
        self.timer_checkStopFalling = wx.Timer()
    '''
    function _002 : bind object event to specific method
    '''
    def _002_bindAction(self):
        #bind action to timer of falling
        self.timer_falling.Bind(wx.EVT_TIMER, self.SLOT001_falling)
        #bind action to timer of check-stop-falling
        self.timer_checkStopFalling.Bind(wx.EVT_TIMER, self.SLOT002_checkStopFalling)
        #bind destroy action to mainMap object
        self.mainMap.evtCollector.Bind(EVT_DESTROY_GAME_OBJ, self.SLOT003_destroy)
    '''
    function _003 : destroy all object used for this class
    '''
    def _003_destroyAllObject(self):
        self.timer_falling.Stop()
        self.timer_falling.Destroy()
        self.timer_checkStopFalling.Stop()
        self.timer_checkStopFalling.Destroy()
        del self
    '''
    function SET001 : set instance variable - posInMap
    '''
    def SET001_posInMap(self, pos):
        self.posInMap = pos
    '''
    function SET002 : set instance variable - isFalling
    '''
    def SET002_isFalling(self, isFall):
        self.isFalling = isFall
    '''
    function SLOT001 : the slot of checking whether this object can fall down / left / right
    ''' 
    def SLOT001_falling(self, event):
        isNext = True
        #method pointer
        judgeFuc = self.mainMap.ACT004_judgePosIsOutOfRange
        objTypeFuc = self.mainMap.GET001_objTypeIn_listCube
        #array of each aspect
        leftPos = (self.posInMap[0], self.posInMap[1] - 1)
        rightPos = (self.posInMap[0], self.posInMap[1] + 1)
        downPos = (self.posInMap[0] + 1, self.posInMap[1])
        leftDownPos = (self.posInMap[0] + 1, self.posInMap[1] - 1)
        rightDownPos = (self.posInMap[0] + 1, self.posInMap[1] + 1)
        #create table of aspect to isLegal
        dirLegal = {str(ASP_LEFT) : not judgeFuc(downPos),
                    str(ASP_RIGHT) : not judgeFuc(rightPos),
                    str(ASP_DOWN) : not judgeFuc(downPos),
                    str(ASP_LEFT_DOWN) : not judgeFuc(leftDownPos),
                    str(ASP_RIGHT_DOWN) : not judgeFuc(rightDownPos)}
        #judge whether it can fall down
        if dirLegal[str(ASP_DOWN)] and (not LIST_IS_OBSTACLE[str(self.objType)][objTypeFuc(downPos)]):
            self.mainMap.ACT002_MoveObj(self.posInMap, downPos, 0)
            self.posInMap = downPos
            self.SET002_isFalling(True)
        #judge hitting the turnable stone wall at down
        elif self.mainMap.GET001_objTypeIn_listCube(downPos) == GAME_OBJ_STONE_WALL_TURNABLE:
            wx.PostEvent(self.mainMap.evtCollector, NewEvt_HitTurnableStoneWall(pos = downPos, callObj = self.objType, isGenProduct = True))
            self.mainMap.ACT003_changeObj(self.posInMap, GAME_OBJ_BLACK, 0)
            self._003_destroyAllObject()
            isNext = False
        #judge whether it can fall left
        elif dirLegal[str(ASP_DOWN)] and dirLegal[str(ASP_LEFT)] and dirLegal[str(ASP_LEFT_DOWN)] and \
        (not LIST_IS_OBSTACLE[str(self.objType)][objTypeFuc(leftPos)]) and \
        (not LIST_IS_OBSTACLE[str(self.objType)][objTypeFuc(leftDownPos)]) :
            downObjType = objTypeFuc(downPos)
            isFallLeft = LIST_DOWN_OBJ_FALL_LR.__contains__(downObjType)
            if isFallLeft :
                self.mainMap.ACT002_MoveObj(self.posInMap, leftPos, 0)
                self.posInMap = leftPos
                self.SET002_isFalling(True)
        #judge whether it can fall right
        elif dirLegal[str(ASP_DOWN)] and dirLegal[str(ASP_RIGHT)] and dirLegal[str(ASP_RIGHT_DOWN)] and \
        (not LIST_IS_OBSTACLE[str(self.objType)][objTypeFuc(rightPos)]) and \
        (not LIST_IS_OBSTACLE[str(self.objType)][objTypeFuc(rightDownPos)]) :
            downObjType = objTypeFuc(downPos)
            isFallRight = LIST_DOWN_OBJ_FALL_LR.__contains__(downObjType)
            if isFallRight :
                self.mainMap.ACT002_MoveObj(self.posInMap, rightPos, 0)
                self.posInMap = rightPos
                self.SET002_isFalling(True)
        if isNext :
            self.timer_falling.Stop()
            self.timer_falling.Start(PublicMethod.ACT003_getRandomNum(900, 1200))
    '''
    function SLOT002 : slot of checking whether this has stopped falling
    ''' 
    def SLOT002_checkStopFalling(self, event):
        downPos = (self.posInMap[0] + 1, self.posInMap[1])
        downObjType = self.mainMap.GET001_objTypeIn_listCube(downPos)
        if self.isFalling and LIST_CREATURE.__contains__(downObjType) : #falling the creature
            self.mainMap.ACT005_bursting(downObjType, downPos)
            self._003_destroyAllObject()
        else :  #judge isFalling
            if self.mainMap.ACT004_judgePosIsOutOfRange(downPos) :  #at bottom of map
                self.SET002_isFalling(False)
            elif LIST_IS_OBSTACLE[str(self.objType)][self.mainMap.GET001_objTypeIn_listCube(downPos)] :  #down is an obstacle
                self.SET002_isFalling(False)
            else :  #start falling
                self.SET002_isFalling(True)
    '''
    function SLOT002 : slot of destroying this object
    ''' 
    def SLOT003_destroy(self, event):
        if not event.isClearAll :
            if event.delObjType == self.objType and self.posInMap[0] == event.delPos[0] and \
            self.posInMap[1] == event.delPos[1] :
                self._003_destroyAllObject()
        else :
            self._003_destroyAllObject()
        event.Skip()